﻿using System;
using System.ComponentModel;
using System.Linq.Expressions;
using Com.PhilChuang.Utils;

namespace Com.PhilChuang.Pmvp.Ui.Views.Impl.ViewModels
{
	public abstract class BaseINPC : INotifyPropertyChanged
	{
		public event PropertyChangedEventHandler PropertyChanged = delegate { };

		//public Dispatcher Dispatcher
		//{ get; set; }

		private void RaisePropertyChanged (string property)
		{
			//if (Dispatcher != null && !Dispatcher.CheckAccess ())
			//{
			//    Dispatcher.BeginInvoke (() => RaisePropertyChanged (property));
			//    return;
			//}

			PropertyChanged (this, new PropertyChangedEventArgs (property));
		}

		protected void RaisePropertyChanged<T> (Expression<Func<T>> propertyExpression)
		{
			RaisePropertyChanged (INPCHelper.GetPropertyName (propertyExpression));
		}
	}

	public static class INPCHelper
	{
		public static String GetPropertyName<T> (Expression<Func<T>> propertyExpression)
		{
			propertyExpression.ThrowIfNull ("propertyExpression");

			if (propertyExpression.Body.NodeType == ExpressionType.MemberAccess)
			{
				var memberExpr = (MemberExpression) propertyExpression.Body;
				return memberExpr.Member.Name;
			}

			if (propertyExpression.Body.NodeType == ExpressionType.Convert
				&& propertyExpression.Body is UnaryExpression
				&& ((UnaryExpression) propertyExpression.Body).Operand.NodeType == ExpressionType.MemberAccess)
			{
				var memberExpr = (MemberExpression) ((UnaryExpression) propertyExpression.Body).Operand;
				return memberExpr.Member.Name;
			}

			throw new Exception ("Expected MemberAccess expression, got {0}".FormatWith (propertyExpression.Body.NodeType));
		}

		public static String GetPropertyName<T> (Expression<Func<T, Object>> propertyExpression)
		{
			propertyExpression.ThrowIfNull ("propertyExpression");

			if (propertyExpression.Body.NodeType == ExpressionType.MemberAccess)
			{
				var memberExpr = (MemberExpression) propertyExpression.Body;
				return memberExpr.Member.Name;
			}

			if (propertyExpression.Body.NodeType == ExpressionType.Convert
				&& propertyExpression.Body is UnaryExpression
				&& ((UnaryExpression) propertyExpression.Body).Operand.NodeType == ExpressionType.MemberAccess)
			{
				var memberExpr = (MemberExpression) ((UnaryExpression) propertyExpression.Body).Operand;
				return memberExpr.Member.Name;
			}

			throw new Exception ("Expected MemberAccess expression, got {0}".FormatWith (propertyExpression.Body.NodeType));
		}
	}
}
